﻿#region Using Statement
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

#endregion

#region COPYRIGHT

/*
    Copyright (c) 2007, 2008, 2009, 2010 
        Roland Rosenkranz (Glatzemann@email.de)
*/

#endregion

#region LICENSE

/*
    This file is part of starLiGHT.Input.

    starLiGHT.Input is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    starLiGHT.Input is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with starLiGHT.Input.  If not, see <http://www.gnu.org/licenses/>.

    
    ADDITIONAL (commercial) LICENSES for starLiGHT.Input are available on request.
*/

#endregion

#region Version Stuff
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 1652                  $:  Revision of last commit *
// * $Author:: glatzemann         $:  Author of last commit   *
// * $Date:: 2010-11-16 07:41:22 #$:  Date of last commit     *
// ************************************************************
#endregion

namespace starLiGHT.Input
{
    /// <summary>
    /// The DeviceManager is responsible for managing the different IControlDevice devices that are supported
    /// on the target platform. It is kind of a factory but at the same time a manager class.
    /// </summary>
    internal class DeviceManager
    {
        List<IControlDevice> devices;

        public DeviceManager()
        {
            devices = new List<IControlDevice>();
#if WINDOWS
            devices.Add(new MouseDevice());             // mouse on windows is always present
            devices.Add(new KeyboardDevice());          // a keyboard is always connected on windows

            devices.Add(new MotionSensingDevice());     // for debugging purposes
#endif

#if WINDOWS_PHONE
            devices.Add(new TouchpadDevice());
            devices.Add(new MotionSensingDevice());
            devices.Add(new PhoneDevice(PlayerIndex.One));
#endif

#if WINDOWS || XBOX360
            for (int i = 0; i < 4; i++)
            {
                GamepadDevice gamepad = new GamepadDevice((PlayerIndex)i);
                devices.Add(gamepad);
#if XBOX360
                devices.Add(new ChatpadDevice(gamepad));
#endif
            }
#endif
        }

        /// <summary>
        /// Updates all devices supported by the executing platform.
        /// </summary>
        /// <param name="gameTime"></param>
        public void Update(GameTime gameTime)
        {
            foreach (IControlDevice device in devices)
            {
                device.Update(gameTime);
            }
        }

        /// <summary>
        /// Returns wheter a given input device type is supported by the current plattform.
        /// </summary>
        /// <param name="deviceType">input device type to be tested.</param>
        /// <returns>true if the input device is available on the current plattform, otherwise it will return false.</returns>
        public bool IsDeviceSupported(DeviceType deviceType)
        {
#if WINDOWS
            return (deviceType == DeviceType.MOUSE || deviceType == DeviceType.KEYBOARD || deviceType == DeviceType.GAMEPAD);
#endif
#if ZUNE || WINDOWS_PHONE
            return (deviceType == DeviceType.TOUCHPAD || deviceType == DeviceType.MOTION_SENSING || deviceType == DeviceType.PHONE);
#endif
#if ZUNE
            return (deviceType == DeviceType.TOUCHPAD || deviceType == DeviceType.MOTION_SENSING);
#endif
#if XBOX
            return (deviceType == DeviceType.GAMEPAD || deviceType == DeviceType.CHATPAD);
#endif
        }

        /// <summary>
        /// Returns a enumerable list of all devices managed by the DeviceManager.
        /// </summary>
        public IEnumerable<IControlDevice> InputDevices
        {
            get
            {
                foreach (IControlDevice device in devices)
                {
                    yield return device;
                }
            }
        }

        /// <summary>
        /// Returns a enumerable list of all devices managed by the DeviceManager of a given type.
        /// </summary>
        /// <param name="deviceType">Type of the devices to be enumerated.</param>
        public IEnumerable<IControlDevice> GetInputDevices(DeviceType deviceType)
        {
            foreach (IControlDevice device in devices)
            {
                if (device.DeviceType == deviceType)
                {
                    yield return device;
                }
            }
        }

        /// <summary>
        /// Returns a device with a specific type and PlayerIndex.
        /// </summary>
        /// <param name="deviceType">Type of the device to be returned.</param>
        /// <param name="playerIndex">PlayerIndex of the device to be returned.</param>
        /// <returns>null if no matching device was found.</returns>
        public IControlDevice GetInputDevice(DeviceType deviceType, PlayerIndex playerIndex)
        {
            foreach (IControlDevice device in GetInputDevices(deviceType))
            {
                if ((device.HasPlayerIndex && device.PlayerIndex == playerIndex) || !device.HasPlayerIndex)
                {
                    return device;
                }
            }

            return null;
        }

#if WINDOWS_PHONE
        public IDigitalControl GetInputDevice(starLiGHT.Input.PhoneButtons button, PlayerIndex playerIndex)
        {
            PhoneDevice phone = GetInputDevice(DeviceType.PHONE, playerIndex) as PhoneDevice;

            if (phone != null)
            {
                switch (button)
                {
                    case PhoneButtons.Back:
                        return phone.Button_Back;
                }
            }

            return null;
        }

        public IPositionalControl GetInputDevice(starLiGHT.Input.MultitouchIndex index, PlayerIndex playerIndex)
        {
            TouchpadDevice touch = GetInputDevice(DeviceType.TOUCHPAD, playerIndex) as TouchpadDevice;

            if (touch != null)
            {
                switch (index)
                {
                    case MultitouchIndex.ONE:
                        return touch.PositionControl(0);
                    case MultitouchIndex.TWO:
                        return touch.PositionControl(1);
                    case MultitouchIndex.THREE:
                        return touch.PositionControl(2);
                    case MultitouchIndex.FOUR:
                        return touch.PositionControl(3);
                }
            }

            return null;
        }
#endif

#if WINDOWS_PHONE || WINDOWS
        public IPositional3DControl GetInputDevice(starLiGHT.Input.AccelerometerType acc, PlayerIndex playerIndex)
        {
            MotionSensingDevice msd = GetInputDevice(DeviceType.MOTION_SENSING, playerIndex) as MotionSensingDevice;

            if (msd != null)
            {
                switch (acc)
                {
                    case AccelerometerType.RAW:
                        return msd.RawAcceleration;
                    case AccelerometerType.SMOOTHED:
                        return msd.SmoothAcceleration;
                }
            }

            return null;
        }
#endif

#if WINDOWS
        public IDigitalControl GetInputDevice(MouseButtons button, PlayerIndex playerIndex)
        {
            MouseDevice mouse = GetInputDevice(DeviceType.MOUSE, playerIndex) as MouseDevice;

            if (mouse != null)
            {
                switch (button)
                {
                    case MouseButtons.LeftButton:
                        return mouse.LeftButton;
                    case MouseButtons.MiddleButton:
                        return mouse.MiddleButton;
                    case MouseButtons.RightButton:
                        return mouse.RightButton;
                    case MouseButtons.XButton1:
                        return mouse.XButton1;
                    case MouseButtons.XButton2:
                        return mouse.XButton2;
                }
            }

            return null;
        }

        public IPositionalControl GetInputDevice(MouseAxis axis, PlayerIndex playerIndex)
        {
            MouseDevice mouse = GetInputDevice(DeviceType.MOUSE, playerIndex) as MouseDevice;

            if (mouse != null)
            {
                switch (axis)
                {
                    case MouseAxis.POSITION:
                        return mouse.ScreenPosition;
                    case MouseAxis.WHEEL:
                        return mouse.MouseWheel;
                }
            }

            return null;
        }

        public IDigitalControl GetInputDevice(Keys key, PlayerIndex playerIndex)
        {
            KeyboardDevice keyboard = GetInputDevice(DeviceType.KEYBOARD, playerIndex) as KeyboardDevice;

            if (keyboard != null)
            {
                return keyboard.GetKey(key);
            }

            return null;
        }
#endif

#if WINDOWS || XBOX
        public IDigitalControl GetInputDevice(Buttons button, PlayerIndex playerIndex)
        {
            GamepadDevice pad = GetInputDevice(DeviceType.GAMEPAD, playerIndex) as GamepadDevice;

            if (pad != null)
            {
                switch (button)
                {
                    case Buttons.A:
                        return pad.Button_A;
                    case Buttons.B:
                        return pad.Button_B;
                    case Buttons.Back:
                        return pad.Button_Back;
                    case Buttons.BigButton:
                        return pad.Button_BigButton;
                    case Buttons.DPadDown:
                        return pad.Button_DPadDown;
                    case Buttons.DPadLeft:
                        return pad.Button_DPadLeft;
                    case Buttons.DPadRight:
                        return pad.Button_DPadRight;
                    case Buttons.DPadUp:
                        return pad.Button_DPadUp;
                    case Buttons.LeftShoulder:
                        return pad.Button_LeftShoulder;
                    case Buttons.LeftStick:
                        return pad.Button_LeftStick;
                    case Buttons.RightShoulder:
                        return pad.Button_RightShoulder;
                    case Buttons.RightStick:
                        return pad.Button_RightStick;
                    case Buttons.Start:
                        return pad.Button_Start;
                    case Buttons.X:
                        return pad.Button_X;
                    case Buttons.Y:
                        return pad.Button_Y;
                }
            }

            return null;
        }

        public IPositionalControl GetInputDevice(GamePadAxis axis, PlayerIndex playerIndex)
        {
            GamepadDevice gp = GetInputDevice(DeviceType.GAMEPAD, playerIndex) as GamepadDevice;

            if (gp != null)
            {
                switch (axis)
                {
                    case GamePadAxis.LEFT_STICK:
                        return gp.LeftThumbstick;
                    case GamePadAxis.RIGHT_STICK:
                        return gp.RightThumbstick;
                    case GamePadAxis.LEFT_TRIGGER:
                        return gp.LeftTrigger;
                    case GamePadAxis.RIGHT_TRIGGER:
                        return gp.RightTrigger;
                }
            }

            return null;
        }

#endif

#if XBOX
        public IDigitalControl GetInputDevice(Keys key, PlayerIndex playerIndex)
        {
            ChatpadDevice chatpad = GetInputDevice(DeviceType.CHATPAD, playerIndex) as ChatpadDevice;

            if (chatpad != null)
            {
                return chatpad.GetKey(key);
            }

            return null;
        }
#endif
    }
}
